/************************************************************************
  			hu/myai/indicators/AbstractIndicator.java - Copyright bozbalint

Here you can write a license for your code, some comments or any other
information you want to have in your generated code. To to this simply
configure the "headings" directory in uml to point to a directory
where you have your heading files.

or you can just replace the contents of this file with your own.
If you want to do this, this file is located at

/opt/kde3/share/apps/umbrello/headings/heading.java

-->Code Generators searches for heading files based on the file extension
   i.e. it will look for a file name ending in ".h" to include in C++ header
   files, and for a file name ending in ".java" to include in all generated
   java code.
   If you name the file "heading.<extension>", Code Generator will always
   choose this file even if there are other files with the same extension in the
   directory. If you name the file something else, it must be the only one with that
   extension in the directory to guarantee that Code Generator will choose it.

you can use variables in your heading files which are replaced at generation
time. possible variables are : author, date, time, filename and filepath.
just write %variable_name%

This file was generated on Sat Mar 14 2009 at 12:14:34
The original location of this file is /home/bozbalint/uml-generated-code/hu/myai/indicators/AbstractIndicator.java
 **************************************************************************/

package hu.myai.api.indicators;

import hu.myai.model.IndicatorVO;
import hu.myai.util.pool.IndicatorPool;

import java.util.ArrayList;
import java.util.List;

/**
 * @author bozbalint
 *
 * Class AbstractIndicator
 */
abstract public class AbstractIndicator extends AbstractIndicatorConsumer implements IndicatorInterface {

    /**
     * Init parameter of the indicator
     */
    protected Double parameter;

    /**
     * Tick is the primary input of the indicator. This is the reference of a
     * tick. Do not modify the value. Let the fwk maintain it.
     * */
    protected String tickSourceID;

    /**
     * The number of the tick data is stored in the tickHistory list I don't
     * want to let it grow till the sky
     * 
     * */
    private static final int maxHistory = 100;

    /**
     * List of the registered triggers and indicators
     */
    protected List<IndicatorConsumerInterface> indicatorConsumerList = new ArrayList<IndicatorConsumerInterface>();

    /**
     * Set the value of indicatorHistory. This is a fix length list of the
     * current indicator history. A house cleaning function take care of the
     * amount of historical data.
     */
    private List<IndicatorVO> indicatorVOHistory = new ArrayList<IndicatorVO>();

    /**
     * Constructor
     * */
    public AbstractIndicator(Double parameter) {
        super();
        this.parameter = parameter;
    }

    /**
     * set up the required indicator and register current indicator
     * */
    protected String register(AbstractIndicator reqIndicator) {

        // sync the indicator with the pool
        IndicatorInterface regIndicator = IndicatorPool.indicatorManager(reqIndicator, tickSourceID);

        // register the trigger into the indicator so it indicator inputs.
        // register the indicator to the expected indicator list
        regIndicator.addIndicatorConsumer(this);
        
        return regIndicator.getName();
    }

    /**
     * Get the value of the indicator parameter
     * 
     * @return the value of parameter
     */
    public Double getParameter() {
        return parameter;
    }

    /**
     * Initialize the indicator and register the necessary triggers. Set the
     * value of Unique name of the indicator Set the tick source id
     * */
    public void init(String name, String tickSourceID) {
        this.tickSourceID = tickSourceID;
        this.name = name;

        // do initialize
        init();
    }

    /**
     * Initialize the indicator and register the necessary triggers.
     */
    abstract public void init();

    /**
     * For push the result to a trigger or indicator. This makes the tight
     * coupling.
     */
    public boolean addIndicatorConsumer(IndicatorConsumerInterface indicatorConsumer) {

        // register itself into the indicator
        if (indicatorConsumer.addIndicatorNameForCheck(name)) {
            if (!indicatorConsumerList.contains(indicatorConsumer)) {
                indicatorConsumerList.add(indicatorConsumer);
                return true;
            } else {
                System.out.println("Error - indicator is already registered: " + indicatorConsumer.getName());
                return false;
            }
        } else {
            System.out.println("Error - indicator is not registered: " + indicatorConsumer.getName());
            return false;
        }
    }

    /**
     * For remove the trigger from the list of indicatior delegation.
     */
    public boolean removeIndicatorConsumer(IndicatorConsumerInterface indicatorConsumer) {
        // unregister itself from the trigger
        if (indicatorConsumer.removeIndicatorNameForCheck(name)) {
            indicatorConsumerList.remove(indicatorConsumer);
            return true;
        } else {
            System.out.println("Error - Trigger is not unregistered: " + indicatorConsumer.getName());
            return false;
        }
    }

    /**
     * Backed feature for check the registered listeners
     */
    public List<IndicatorConsumerInterface> getIndicatorConsumerList() {
        return indicatorConsumerList;
    }

    @Override
    protected void startCalculation() {
        // do the calculation only if all expected indicator is set
        if (checkIndicatorCompleteness() && isTickCompleteness) {

            // not a new tick any more
            isTickCompleteness = false;

            // do the indicator calculation
            IndicatorVO indicator = indicatorCalculation();

            // clean up the indicator buffer
            indicatorMap.clear();

            // add indicator history
            if (indicator != null) {
                indicatorVOHistory.add(0, indicator);

                // clean up the history buffer
                indicatorVOHistoryHistoryCleanup();
            }

            // propegate the calculated indicator
            propegateIndicator(indicator);
        }
    }

    /**
     * implements the feature of the class, do the calculation
     */
    abstract protected IndicatorVO indicatorCalculation();

    /**
     * This check the size of indicatorVO history list. If the list size is
     * larger then the given value it truncates it. This take care of no heap
     * memory problem.
     */
    private void indicatorVOHistoryHistoryCleanup() {
        while (indicatorVOHistory.size() > maxHistory) {
            indicatorVOHistory.remove(0);
        }
    }

    /**
     * Propagate indicator to all registered consumers
     * */
    protected void propegateIndicator(IndicatorVO indicator) {
        for (IndicatorConsumerInterface indicatorConsumer : indicatorConsumerList) {
            indicatorConsumer.addIndicator(name, indicator);
        }
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("[" + name + "]\n");
        sb.append("Registered consumers: ");
        for (IndicatorConsumerInterface indicatorConsumer : indicatorConsumerList) {
            sb.append("\n\t " + indicatorConsumer.getName());
        }

        return sb.toString();
    }
}
